package cc.yaomm.common.basic.excel.base;

import cc.yaomm.common.basic.base.SuperPOJO;
import cc.yaomm.common.basic.excel.base.SuperParamContext;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.metadata.Head;
import com.google.common.base.Joiner;
import lombok.Data;
import org.hibernate.validator.HibernateValidator;
import org.springframework.util.CollectionUtils;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.groups.Default;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Created by XQL on 2021/10/13.
 */
@Data
@ExcelIgnoreUnannotated
public class SuperImportVO extends SuperPOJO {

    protected Integer rowIdx; //对应excel的行号

    protected boolean success = true; //是否成功

    protected String message = "导入成功"; //错误消息

    protected Set<Integer> columnIdxes = new HashSet<>(); //错误消息列

    //验证器
    protected final Validator validator = Validation.byProvider(HibernateValidator.class)
            .configure().failFast(true).buildValidatorFactory().getValidator();

    /**
     * <p>@Description : 验证数据（基础验证，扩展验证，重复验证） </p>
     * <p>@Author : QiLin.Xing </p>
     * <p>@Date : 2022/1/18 10:03 </p>
     *
     * @param paramContext 参数上下文
     * @param dataSet      验重数据
     * @return 通过则true, 不通过则false
     */
    public boolean valid(SuperParamContext paramContext, Set<String> dataSet) {
        return validBase(paramContext.getHeadPropMap()) && validExtend(paramContext) && validRepeat(paramContext, dataSet);
    }

    /**
     * <p>@Description : 验证数据（基础验证） </p>
     * <p>@Author : QiLin.Xing </p>
     * <p>@Date : 2022/1/18 10:01 </p>
     *
     * @return 通过则true, 不通过则false
     */
    private boolean validBase(Map<String, Head> headPropMap) {
        // 校验.
        Set<? extends ConstraintViolation> errors = validator.validate(this, Default.class);
        if (CollectionUtils.isEmpty(errors)) {
            return true;
        }
        this.message = errors.stream().map(x -> {
            Head head = headPropMap.get(x.getPropertyPath().toString());
            if (Objects.nonNull(head)) {
                this.columnIdxes.add(head.getColumnIndex());
            }
            return Joiner.on("：").skipNulls().join(Joiner.on("-").skipNulls().join(head.getHeadNameList()), x.getMessage());
        }).collect(Collectors.joining("；"));
        this.success = false;
        return false;
    }

    /**
     * <p>@Description : 验证数据(扩展验证） </p>
     * <p>@Author : QiLin.Xing </p>
     * <p>@Date : 2022/1/18 9:19 </p>
     *
     * @param paramContext 参数上下文
     * @return 通过则true, 不通过则false
     */
    protected boolean validExtend(SuperParamContext paramContext) {
        return true;
    }

    /**
     * <p>@Description : 验证数据是否重复（Excel表内）,依赖于表头，不能为空</p>
     * <p>@Author : QiLin.Xing </p>
     * <p>@Date : 2022/1/18 9:36 </p>
     *
     * @param dataSet 验重数据
     * @return 通过则true, 不通过则false
     */
    private boolean validRepeat(SuperParamContext paramContext, Set<String> dataSet) {
        Map<String, Object> repeatMap = this.getRepeatMap();
        if (CollectionUtils.isEmpty(repeatMap)) {
            return true;
        }

        String repeatValue = Joiner.on(",").skipNulls().join(repeatMap.values());
        if (!dataSet.contains(repeatValue)) { //不包含
            dataSet.add(repeatValue);
            return true;
        }

        this.message = Joiner.on("+").skipNulls().join(repeatMap.keySet()).concat("在表格中存在重复数据");
        repeatMap.keySet().forEach(x -> {
            Head head = paramContext.getHeadNameMap().get(x);
            if (Objects.nonNull(head)) {
                this.columnIdxes.add(head.getColumnIndex());
            }
        });
        this.success = false;
        return false;
    }

    /**
     * <p>@Description : 验证表内重复的列及头 </p>
     * <p>@Author : QiLin.Xing </p>
     * <p>@Date : 2022/1/18 14:48 </p>
     *
     * @return 返回表头名称-列数据的Map
     */
    protected Map<String, Object> getRepeatMap() {
        return null;
    }

    /**
     * <p>@Description : 合并表头，涉及多行表头的情况 </p>
     * <p>@Author : QiLin.Xing </p>
     * <p>@Date : 2022/1/18 17:30 </p>
     *
     * @param headName 多行表头，注意顺序(按照行号递增)
     * @return 返回组合后的头名称，数据校验的地方用到
     */
    protected String mergeHeadName(String... headName) {
        return Joiner.on("-").skipNulls().join(headName);
    }

}
